
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.Barcode128;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import integrisign.desktop.Base64Format;
import integrisign.desktop.DeskSign;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.FileUtils;

/**
 * Clase que será la encargada de realizar las tareas sobre un pdf.
 * @author epindado
 */
public class TratarPDF {
    /**
     * Método encargado de realizar la firma digital de un pdf
     * @param rutaEntrada
     * @param rutaSalida
     * @param rutaFirma 
     */
    public void firmaDigitalPDF (File ficheroEntrada, String rutaSalida, String rutaFirma) throws DocumentException{
        PdfReader reader = null;
        PdfStamper stamper = null;
        try {
            //Establecemos qué tipo de keystore usaremos
            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
            ks.load(new FileInputStream(rutaFirma), "password".toCharArray());
            String alias = (String)ks.aliases().nextElement();
            PrivateKey key = (PrivateKey)ks.getKey(alias, "password".toCharArray());
            Certificate[] chain = ks.getCertificateChain(alias);
            byte[] arrayFicheroEntrada = FileUtils.readFileToByteArray(ficheroEntrada);
            reader = new PdfReader(arrayFicheroEntrada);
            FileOutputStream fout = new FileOutputStream(rutaSalida);
            stamper = PdfStamper.createSignature(reader, fout, '\0');

            PdfSignatureAppearance sap = stamper.getSignatureAppearance();
            sap.setCrypto(key, chain, null, PdfSignatureAppearance.SELF_SIGNED);
            sap.setReason("Soy el autor");
            sap.setLocation("Madrid");
            //Se hace visible la firma
            int maxPagina = reader.getNumberOfPages();
            sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), maxPagina, null);

         } catch (UnrecoverableKeyException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (CertificateException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (KeyStoreException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception e) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                if (stamper != null){
                    try {
                        stamper.close();
                    } catch (DocumentException ex) {
                        Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                if (reader != null){
                    reader.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    /**
     * Método encargado de firmar el documento pdf
     * @param pathpdf
     * @param fileKey
     * @param fileKeyPassword
     * @return 
     */
    public boolean sign(String pathpdf, String fileKey, String fileKeyPassword) {
        try {
            //Crea un KeyStore
            KeyStore ks = KeyStore.getInstance("pkcs12");
            //Carga Certificado
            ks.load(new FileInputStream(fileKey), fileKeyPassword.toCharArray());
            String alias = (String)ks.aliases().nextElement();
            //Recupera Clave Privada
            PrivateKey key = (PrivateKey)ks.getKey(alias, fileKeyPassword.toCharArray());
            //Recupera Cadena de Certificacion si existe
            Certificate[] chain = ks.getCertificateChain(alias);
            //Lee Documento PDF y crea archivo de salida con otro nombre para no pisar el original
            PdfReader pdfReader = new PdfReader((new File(pathpdf)).getAbsolutePath());
            File outputFile = new File(pathpdf + ".signed.pdf");
            // Crea la firma en el objeto PdfStamper de la librería iText
            PdfStamper pdfStamper;
            pdfStamper = PdfStamper.createSignature(pdfReader, null, '\0', outputFile);
            PdfSignatureAppearance sap = pdfStamper.getSignatureAppearance();
            sap.setCrypto(key, chain, null, PdfSignatureAppearance.SELF_SIGNED);
            sap.setReason("Test GGS");
            sap.setLocation("Location");
            // Posiciona la Firma
            int maxPagina = pdfReader.getNumberOfPages();
            sap.setVisibleSignature(new Rectangle(100, 100, 200, 200), maxPagina, "sign_ggs");
            pdfStamper.setFormFlattening(true);
            pdfStamper.close();
        } catch (Exception key) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, key);
            return false;
        }
        return true;
    }

    /**
     * Método encargado de recuperar la imagen almacenada en el objeto DeskSign y de
     * insertar un código de barras con la información del Hash del fichero zip
     * @param deskSign
     */
    public void insertarImagen (DeskSign deskSign, String hashZip, String rutaEntrada, File archivoTemporal) {

        PdfReader reader = null;
        PdfStamper stamper = null;
        try {
            reader = new PdfReader(rutaEntrada);
            stamper = new PdfStamper(reader, new FileOutputStream(archivoTemporal));

            // Inserción de imagen de la firma
            String signstr = deskSign.getString();
            Base64Format b64fmt = new Base64Format();
            // la imagen en el objeto desksign está en base64
            byte[] jpegbytes = b64fmt.decode64(deskSign.getJpegString(signstr, 100, 65, 100));
            Image img = Image.getInstance(jpegbytes);
            // Posicion absoluta
            img.setAbsolutePosition(250f, 50f);
            int maxPagina = reader.getNumberOfPages();
            PdfContentByte underContent = stamper.getUnderContent(maxPagina);
            underContent.addImage(img, true);

            // Inserción código de barras
            Barcode128 code128 = new Barcode128();
            code128.setCode(hashZip);
            code128.setSize(15);
            code128.setBaseline(13);
            code128.setFont(BaseFont.createFont(BaseFont.HELVETICA_BOLD, "winansi", true) );
            Image imageCode = code128.createImageWithBarcode(underContent, null, null);
            imageCode.setAbsolutePosition(370f, 50f);
            imageCode.scaleAbsolute(200f, 45f);
            underContent.addImage(imageCode);

        } catch (BadElementException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (MalformedURLException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (DocumentException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception e) {
            Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                if (stamper != null){
                    try {
                        stamper.close();
                    } catch (DocumentException ex) {
                        Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                if (reader != null){
                    reader.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(FirmaPDF.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}
